package controller;

import java.util.*;

/**
 *
 * @author DAVINCI
 */
public class EstadisticaController {

    /**
     * @param matriz Es la matriz que contiene en cada una de sus celdas un
     * arreglo de tipo double
     *
     */
    
//----------------------- Estadistica de Friedman ----------------------------//

    public static double estadisticaDeFriedman(ArrayList<Double>[][] matriz) {
        //para Ks iguales
        double[] RpuntoJpunto = calcularRpuntoJpunto(obtenerMatrizRangos(matriz));
        /**
         * n columnas, m filas
         */
        int m = matriz.length;
        int n = matriz[0].length;
        /**
         * k es el tamaño del arreglo X interno de cada celda. k es constante en
         * este caso
         */
        int k = matriz[0][0].size();

        double sumatoriaRpuntoJpunto = 0;
        for (int j = 0; j < RpuntoJpunto.length; j++) {
            sumatoriaRpuntoJpunto += Math.pow(RpuntoJpunto[j], 2);
        }

        double K = (12 * sumatoriaRpuntoJpunto) / (n * m * k * k * (m * k + 1)) - 3 * n * (m * k + 1);

        return K;
//        for(int i=0;i<matriz.length;i++){
//            for(int j=0;j<matriz[0].length;j++){  
//                
//                System.out.println("celda i: "+i+" j: "+j+" k: "+k);    
//            }
//        }


    }    
    
    public static double estadisticaDeFriedmanGeneralizada(ArrayList<Double>[][] matriz) {
        double suma = 0;
        for(int fila=0; fila<matriz.length;fila++){
            for(int columna=0; columna<matriz[0].length;columna++){
                
                suma += (1-(matriz[fila][columna].size()/calcularMIPunto(matriz, fila)))*
                        (Math.pow(((calcularRIJPunto(obtenerMatrizRangos(matriz), fila, columna))-esperanzaRIJP(matriz, fila, columna)
                         /Math.sqrt(varianzaRIJP(matriz, fila, columna))),2.0));
            }
        }
        return suma;
    }

//------------------------ Estadistica J -------------------------------------//    
    static void estadisticaJ() {
        
        
    }
    
//--------------------------- OBTENER TIPOS DE MATRICES ----------------------//
    
    public static ArrayList<Integer>[][] obtenerMatrizRangos(ArrayList<Double>[][] matriz){
            ArrayList<Integer>[][] matrizDeRangos = new ArrayList[matriz.length][matriz[0].length];
            ArrayList<ElementodeX> temp = new ArrayList<ElementodeX>();

        //calcular matriz de rangos
        for (int fila = 0; fila < matriz.length; fila++) {
            for (int columna = 0; columna < matriz[0].length; columna++) {
                Iterator ite = matriz[fila][columna].iterator();
                int k = 0;

                while (ite.hasNext()) {
                    temp.add(new ElementodeX(fila, columna, k, (Double) ite.next()));
                    k++;
                }
                //se inicializa la matriz de randgos con un arraylist con una capacidad para guardar
                //los valores que tenia la matriz de la doble via...
                matrizDeRangos[fila][columna] = new ArrayList<Integer>(k);
                for (int i = 0; i < k; i++) {
                    matrizDeRangos[fila][columna].add(0);
                }
            }
            //Ya se tienen todos los valores del bloque (fila) en temp
            Collections.sort(temp);
            Iterator ite = temp.iterator();
            //recorremos todo el arraylist y guardamos en la posicion correcta
            //el valor de la posicion en el arreglo ordenado
            int pos = 1;
            while (ite.hasNext()) {
                ElementodeX elem = (ElementodeX) ite.next();
                matrizDeRangos[elem.getFila()][elem.getColumna()].set(elem.getPosicion(), pos);
                pos++;
            }
            temp.clear();
        }
        
        
        //imprimir la matriz de rangos
        for (int i = 0; i < matrizDeRangos.length; i++) {
            for (int j = 0; j < matrizDeRangos[0].length; j++) {
                Iterator it =matrizDeRangos[i][j].iterator();
                int k=0;
                while(it.hasNext()){
                System.out.println("Celda ("+i+","+j+") Valor "+k+": "+it.next());
                k++;
                }
            }  
        }
        /////////
        return matrizDeRangos;
    }

    
    public static ArrayList<Integer>[][] obtenerMatrizSecuencias(ArrayList<Double>[][] matriz){
        ArrayList<Integer>[][] matrizDeSecuencias = new ArrayList[matriz.length][matriz[0].length];
        ArrayList<ElementodeX> temp = new ArrayList<ElementodeX>();

        //Inicializando Matriz de secuencias
        for (int fila = 0; fila < matriz.length; fila++) {
            for (int columna = 0; columna < matriz[0].length; columna++) {
                Iterator ite = matriz[fila][columna].iterator();
                int k = 0;

                while (ite.hasNext()) {
                    temp.add(new ElementodeX(fila, columna, k, (Double) ite.next()));
                    k++;
                }
                //se inicializa la matriz de randgos con un arraylist con una capacidad para guardar
                
                //los valores que tenia la matriz de la doble via...
                matrizDeSecuencias[fila][columna] = new ArrayList<Integer>(k);
                for (int i = 0; i < k; i++) {
                    matrizDeSecuencias[fila][columna].add(0);
                }
            }
            //Ya se tienen todos los valores del bloque (fila) en temp
            Collections.sort(temp);
            Iterator ite = temp.iterator();
            //recorremos todo el arraylist y guardamos en la posicion correcta
            //el valor de la posicion en el arreglo ordenado
            int cont = 0;
            int sec = 0;
            int columnaAnterior = -1;
            while (ite.hasNext()) {
                ElementodeX elem = (ElementodeX) ite.next();
                
                //Se validan las columnas para incrementar el valor de la secuen-
                //cia y almacenarlo en la matriz de secuencias
                if(elem.getColumna()!=columnaAnterior){
                    sec++;
                }
                columnaAnterior=elem.getColumna();
                
                matrizDeSecuencias[elem.getFila()][elem.getColumna()].set(elem.getPosicion(), sec);
                cont++;
            }
                //EN LA TEORIA SE TIENE:
                //189   01256789  21112323 12223456 256
                //267                               234
                //50                                21
            
            //Remueve todos los elementos
            temp.clear();
            
        }
        //imprimir la matriz de Secuencias
        for (int i = 0; i < matrizDeSecuencias.length; i++) {
            for (int j = 0; j < matrizDeSecuencias[0].length; j++) {
                Iterator it =matrizDeSecuencias[i][j].iterator();
                int k=0;
                while(it.hasNext()){
                System.out.println("Celda ("+i+","+j+") Valor "+k+": "+it.next());
                k++;
                }
            }  
        }
        /////////
        return matrizDeSecuencias;
    }
    
//------------------------ OPERACIONES CON MATRICES --------------------------//
    //Validador de expresiones es llamada pjp
    public static double[] calcularRpuntoJpunto(ArrayList<Integer>[][] matriz) {


        //Calcular el vector 
        double suma;
        double[] vectorRpuntoJpunto = new double[matriz[0].length];

        for (int columna = 0; columna < matriz[0].length; columna++) {
            suma = 0;
            for (int fila = 0; fila < matriz.length; fila++) {
                Iterator ite = matriz[fila][columna].iterator();
                while (ite.hasNext()) {
                    suma += (Integer) ite.next();
                }
                vectorRpuntoJpunto[columna] = suma;
            }
        }
        return vectorRpuntoJpunto;
    }
    
    //Validador de expresiones es llamada ijp
    public static double calcularRIJPunto(ArrayList<Integer>[][] matriz, int fila, int columna){
        //Calcular el vector 
        double suma=0;
        double valorRIJPunto = 0;

        Iterator ite = matriz[fila][columna].iterator();
            while (ite.hasNext()) {
                suma += (Integer) ite.next();
            }
            valorRIJPunto = suma;
        return valorRIJPunto;
    }
    
    //Validador de expresiones es llamada mip
    //Calcular la suma de todos los tamaños de las celdas de la fila i
    public static double calcularMIPunto(ArrayList<Double>[][] matriz, int fila){
        //Calcular el vector 
        double suma=0;
        for(int columna=0;columna<matriz[0].length; columna++){
                suma += matriz[fila][columna].size();
        }
        return suma;
    }
    
    //Calcula la suma de todos los tamaños de las celdas de la columna j
    public static double calcularMPuntoJ(ArrayList<Double>[][] matriz, int columna){
        int suma = 0;
        for(int fila=0; fila<matriz.length; fila++){
            suma += matriz[fila][columna].size();
        }
        return suma;
        
    }
    
    public static double esperanzaRIJP(ArrayList<Double>[][] matriz,int fila, int columna){
        return calcularMPuntoJ(matriz, columna)*((calcularMIPunto(matriz, fila)+1)/2);
    }

    public static double varianzaRIJP(ArrayList<Double>[][] matriz,int fila, int columna){
        return calcularMPuntoJ(matriz, columna)*((calcularMIPunto(matriz, fila)-matriz[fila][columna].size())
                *(calcularMIPunto(matriz, fila)+1)/12);
    }
//------------------------------- PRUEBAS ------------------------------------//
    
    public static void prueba() {
        ArrayList<Double>[][] matriz = new ArrayList[1][3];
        for (int i = 0; i < matriz.length; i++) {
            for (int j = 0; j < matriz[0].length; j++) {
                matriz[i][j] = new ArrayList<Double>();
            }
        }
        matriz[0][0].add(1.0);
        matriz[0][0].add(2.0);
        matriz[0][0].add(5.0);
        matriz[0][1].add(8.0);
        matriz[0][1].add(6.0);
        matriz[0][1].add(0.0);
        matriz[0][2].add(9.0);
        matriz[0][2].add(7.0);
        
        
        double[] rpJp=calcularRpuntoJpunto(obtenerMatrizSecuencias(matriz));
        for (int i = 0; i < rpJp.length; i++) {
          System.out.println("Secuencia columna"+i+": "+rpJp[i]+"");  
        }
        double friedman=estadisticaDeFriedman(matriz);
        System.out.println("Estadistica de friedman"+friedman);

    }
}
